数据库的锁是用来解决并发问题。作为用户共享的资源,当出现并发访问的时候,数据库需要合理的控制资源的访问规则,而数据库锁就是来实现这些访问规则的重要数据结构。
锁的分类
- 全局锁
- 表级锁
- 行锁
全局锁
对整个数据库加锁,数据库更新语句(更删改),数据定义语句(建表,修改表结构)等操作都会被阻塞。
应用场景
全库逻辑备份(保证数据逻辑一致性)
表级锁
- 表锁
加锁:lock tables … read/write
释放锁:手动unlock tabls,或者客户端断开的时候字段释放
影响:lock tables控制并发,锁住整张表,影响比较大。
- 元数据锁(meta data lock,MDL)
Mysql 5.5 引入了MDL,当对一个表做增删改查的时候,加MDL读锁,当对标做结构变更操作的时候,加MDL写锁。
- 读锁之间不互斥。
- 读写锁与写锁之间互斥。保证表结构操作的安全性
案例
给表加字段导致系统,导致数据库挂了。
- session A执行读取数据操作,这时会对表加一个MDL读锁
- session B执行读取数据操作,这时会对表加一个MDL读锁,但是读锁之间不互斥,所以能够正常查询出数据。
- session C这时候给表添加字段,由于session A还没有释放MDL读锁,所以session C拿不到写锁,因此会被阻塞
- session D由于session C的写锁请求被阻塞,那么session D的读取请求也会被阻塞
后果: 这个表的查询语句频繁,而且客户端还有重试机制,会导致整个库的线程很快爆满。MDL锁需要等到事务提交之后再释放。
如何安全的给表加字段
- 查询当前执行的事务,如果有长事务在执行,则先暂停DDL,或者kill掉这个长事务。
- alter table设置等待时间,在指定时间内能拿到MDL写锁最好,拿不到则退出,不阻塞后面的业务语句,后面再次重试。